/**
 * @title PagerInterceptor.java
 * @package com.hw.one.core.mybatis
 * @author 刘晓斌
 * @create_time 2014年10月30日 下午2:38:41
 * <p>Copyright 河南汉威电子股份有限公司软件部 Corporation 2014</p>
 */
package com.hw.one.collect.mybatis;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * <p>
 * Mybatis分页拦截器<br>
 * </p>
 */
@Intercepts({@Signature(type=Executor.class,method="query",args={MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class})})
public class PagerInterceptor implements Interceptor {
	
	/**
	 * 从Mybatis配置文件中获取数据库类型参数
	 */
	private String dataBaseType;
	
	/*
	(non-Javadoc)
	 * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
	 */
	public Object intercept(Invocation invocation) throws Throwable {
		Object[] args = invocation.getArgs();
		MappedStatement mappedStatement = (MappedStatement) args[0];
		Object params = args[1];
		BoundSql boundSql = mappedStatement.getBoundSql(params);
		// 原sql
		String sql = boundSql.getSql();
		// 参数
		Object paramObj = boundSql.getParameterObject();

		if (paramObj instanceof Map && !(paramObj instanceof StrictMap)) {
			@SuppressWarnings("rawtypes")
			Map paramMap = (Map) paramObj;

			// 查询条数
			if (paramMap.get("selectCount") != null
					&& (Boolean) (paramMap.get("selectCount"))) {
				sql = SQLUtil.getSelectCountSQL(sql);
			}
			else if (paramMap.get("page") != null && (Boolean)paramMap.get("page")) {
				// 处理排序
//				sql = SQLUtil.getOrderBySQL(sql, (String)paramMap.get("orderColumm"),(String)paramMap.get("orderType"));
				if(paramMap.get("orders") != null){
					sql = SQLUtil.getOrderBySQL(sql, (List<Map<String, String>>)paramMap.get("orders"));
				}
				if("mysql".equals(dataBaseType)){
					// Oracle 分页语句
					sql = SQLUtil.getMysqlPagerSQL(sql, (Integer)paramMap.get("start"), (Integer)paramMap.get("end"));
				}
				else if("oracle".equals(dataBaseType)){
					// Oracle 分页语句
					sql = SQLUtil.getOraclePagerSQL(sql,(Integer)paramMap.get("start"), (Integer)paramMap.get("end"));
				}
				else if("sqlserver".equals(dataBaseType)){
					sql = SQLUtil.getSqlserverPagerSQL(sql, (Integer)paramMap.get("start"), (Integer)paramMap.get("end"));
				}
			}
			BoundSql newBoundSql = createBoundSql(mappedStatement, boundSql, sql);
			Builder builder = createBuilder(mappedStatement, newBoundSql);
			MappedStatement newMappedStatement = builder.build();
			args[0] = newMappedStatement;
		}
		return invocation.proceed();
	}

	/*
	(non-Javadoc)
	 * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
	 */
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	/*
	(non-Javadoc)
	 * @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
	 */
	public void setProperties(Properties properties) {
		if(this.dataBaseType == null){
			this.dataBaseType = properties.getProperty("dataBaseType");
		}
	}
	
	private BoundSql createBoundSql(MappedStatement mappedStatement,
			BoundSql boundSql, String sql) {
		return new BoundSql(mappedStatement.getConfiguration(), sql,
				boundSql.getParameterMappings(), boundSql.getParameterObject());
	}

	private Builder createBuilder(MappedStatement mappedStatement,
			final BoundSql boundSql) {
		Builder builder = new Builder(mappedStatement.getConfiguration(),
				mappedStatement.getId(), new SqlSource() {
					public BoundSql getBoundSql(Object parameterObject) {
						return boundSql;
					}
				}, mappedStatement.getSqlCommandType())
				.cache(mappedStatement.getCache())
				.useCache(mappedStatement.isUseCache())
				.fetchSize(mappedStatement.getFetchSize())
				.flushCacheRequired(mappedStatement.isFlushCacheRequired())
				.keyGenerator(mappedStatement.getKeyGenerator())
				.parameterMap(mappedStatement.getParameterMap())
				.timeout(mappedStatement.getTimeout())
				.resource(mappedStatement.getResource())
				.resultMaps(mappedStatement.getResultMaps())
				.resultSetType(mappedStatement.getResultSetType())
				.statementType(mappedStatement.getStatementType());

		if (mappedStatement.getKeyProperties() != null) {
			for (String keyProperty : mappedStatement.getKeyProperties()) {
				builder.keyProperty(keyProperty);
			}
		}
		return builder;
	}

	public void setDataBaseType(String dataBaseType) {
		this.dataBaseType = dataBaseType;
	}
}
